home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / editors / mutt / me2s_pl7.zoo / mu_edit2 / mc2 / code.c next >
Encoding:
C/C++ Source or Header  |  1992-08-26  |  16.1 KB  |  589 lines

  1. /*
  2.  * code.c : code generation for MC2
  3.  */
  4.  
  5. /* Copyright 1990, 1991, 1992 Craig Durland
  6.  *   Distributed under the terms of the GNU General Public License.
  7.  *   Distributed "as is", without warranties of any kind, but comments,
  8.  *     suggestions and bug reports are welcome.
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #include <dtable.h>
  14. #include <os.h>
  15. #include "mm.h"
  16. #include "mc.h"
  17.  
  18. #define OPNAMES 1
  19. #include "opcode.h"
  20.  
  21. /* ******************************************************************** */
  22. /* ****************** Initialize the Code Generator ******************* */
  23. /* ******************************************************************** */
  24.  
  25. static int add_string();
  26. static void gennum8();
  27.  
  28.     /* Put a HALT at address 0.  This will stop any programs that that have
  29.      *   somehow successfully compiled with unresolved jump addresses (which
  30.      *   are 0).
  31.      * The real reason is to increment the PC.  I don't want code at address
  32.      *   0 because I'm using that to indicate an unresolved address.  Kinda
  33.      *   slimey but its only 1 wasted byte.
  34.      */
  35. void init_code_generater()
  36. {
  37.   gennum8(HALT);
  38. }
  39.  
  40. /* ******************************************************************** */
  41. /* ***************** code generation ********************************** */
  42. /* ******************************************************************** */
  43.  
  44. extern address getlabel();
  45. extern char ebuf[], *spoof(), *typename();
  46. extern FILE *lstfile;            /* in mc.c */
  47. extern MuttCmd muttcmds[];
  48. extern oMuttCmd omuttcmds[];
  49. extern int xtn, msize, omsize;
  50. extern void addfref();
  51.  
  52. static void call_unknown_pgm();
  53.  
  54. address entrypt = 0;        /* address of HALT */
  55. static address pc = 0;        /* Somebody puts a HALT here */
  56.  
  57. static declare_and_init_dTable(compiled_code,uint8);
  58.  
  59. address pcaddr() { return pc; }
  60.  
  61. unsigned int codesize() { return pc; }
  62.  
  63. static void codger(n)
  64. {
  65.   if (xpand_dTable(&compiled_code, n, 8192, 4096)) return;
  66.   printf("Out of memory! Can't expand code.\n");
  67.   exit(1);
  68. }
  69.  
  70. #define LST if (lstfile) lst
  71.  
  72. void lst(opcode,text) char *text;
  73. {
  74.   if (lstfile)
  75.     fprintf(lstfile,"%4u:     %-15s %s\n",pc,opname[opcode],text);
  76. }
  77.  
  78. #define GENNUM8(n) compiled_code.table[pc++] = (n)
  79.  
  80. static void gennum8(n) { codger(1); GENNUM8(n); }
  81.  
  82. static void gennum16(n)
  83.   { codger(2); PUT_INT16(&compiled_code.table[pc],n);  pc += sizeof(int16); }
  84.  
  85. static void gennum32(n) int32 n;
  86.   { codger(4); PUT_INT32(&compiled_code.table[pc],n);  pc += sizeof(int32); }
  87.  
  88. #define GENADDR(pc,addr) \
  89.     PUT_INT16(&compiled_code.table[pc],(int16)((addr) -(pc) +1))
  90.  
  91. static void genaddr(addr,jmpaddr) address addr, jmpaddr;
  92.   { codger(2); GENADDR(addr,jmpaddr); pc += sizeof(int16); }
  93.  
  94. void goaddr(opcode,addr,msg) char *msg; address addr;
  95. {
  96.   LST(opcode,spoof(ebuf,"%d (%s)",addr,msg));
  97.   gennum8(opcode); genaddr(pc,addr);
  98. }
  99.  
  100. void gojmp(opcode,label)
  101. {
  102.   int n;
  103.  
  104.   LST(opcode,spoof(ebuf,"L%d",label));
  105.   gennum8(opcode);
  106.   if ((n = getlabel(label)) == NIL) addfref(pc,label);
  107.   genaddr(pc,n);
  108. }
  109.  
  110. void genop(opcode) { LST(opcode,""); gennum8(opcode); }
  111.  
  112. void gostr(opcode,string) char *string;
  113. {
  114.   int offset;
  115.  
  116.   if (lstfile)
  117.   {
  118.     unsigned char *ptr = (unsigned char *)string;
  119.     char *qtr = ebuf;
  120.     *qtr++ = '"';
  121.     while (*ptr)
  122.     {
  123.       if (iscntrl(*ptr)) { *qtr++ = '^'; *qtr++ = *ptr +0x40; }
  124.       else *qtr++ = *ptr;
  125.       ptr++;
  126.     }
  127.     *qtr++ = '"'; *qtr = '\0';
  128.     lst(opcode,ebuf);
  129.   }
  130.   switch (opcode)
  131.   {
  132.     case RVSTR:    offset = add_string(string,TRUE);       break;
  133.     case PUSHNAME: offset = NIL; call_unknown_pgm(string); break;
  134.     default: bitch("Unknown opcode to gostr()");
  135.   }
  136.   gennum8(opcode); gennum16(offset);
  137. }
  138.  
  139. void gonum8(opcode,n)
  140. {
  141.   if (lstfile)
  142.   {
  143.     switch(opcode)
  144.     {
  145.       case RVBOOL: lst(opcode,n ? "TRUE" : "FALSE"); break;
  146.       case TYPECHECK: case GETRVAR: case SETRVAR:
  147.         lst(opcode,typename(n)); break;    
  148.       default: lst(opcode,spoof(ebuf,"%d",n));
  149.     }
  150.   }
  151.   gennum8(opcode); gennum8(n);
  152. }
  153.  
  154. void gonum16(opcode,n)
  155. {
  156.   extern char *lookup_ext_token_by_value();    /* in token.c */
  157.  
  158.   if (lstfile)
  159.   {
  160.     switch(opcode)
  161.     {
  162.       int j;
  163.       case PUSHTOKEN:
  164.     for (j = 0; j < omsize; j++) if (omuttcmds[j].token == n) break;
  165.     lst(opcode,spoof(ebuf,"%s (%d)",omuttcmds[j].name,n));
  166.     break;
  167.       case PUSHXT:
  168.     lst(opcode,spoof(ebuf,"%s (%d)",lookup_ext_token_by_value(n), n));
  169.     break;
  170.       default: lst(opcode,spoof(ebuf,"%d",n));
  171.     }
  172.   }
  173.   gennum8(opcode); gennum16(n);
  174. }
  175.  
  176. void gonumx(n) int32 n;
  177. {
  178.   unsigned int opcode, type;
  179.   int16 z = n;
  180.  
  181.   if (0 <= n && n < 128) { type = INT8; opcode = RVNUM8; }
  182.   else
  183.     if (n == z) { type = INT16; opcode = RVNUM16; }
  184.     else { type = INT32; opcode = RVNUM32; }
  185.  
  186.   lst(opcode,spoof(ebuf,"%ld (%s)",n,typename(type)));
  187.  
  188.   gennum8(opcode);
  189.   switch (type)
  190.   {
  191.     case INT8:  gennum8((int)n); break;
  192.     case INT16: gennum16((int)z); break;
  193.     case INT32: gennum32(n); break;
  194.   }
  195. }
  196.  
  197. void go2num(opcode,n1,n2)
  198. {
  199.   LST(opcode,spoof(ebuf,"%d (%s)",n2,typename(n1)));
  200.   gennum8(opcode); gennum8(n1); gennum16(n2);
  201. }
  202.  
  203. void genobj(opcode, scope, type, offset)
  204. {
  205.   scope = (scope == GLOBAL);        /* 1 or 0 for MM */
  206.  
  207.   lst(opcode,spoof(ebuf,"%s %s %d", scope ? "global" : "local",
  208.     typename(type), offset));
  209.  
  210.   if (type == STRING) type = OSTRING;
  211.  
  212.   gennum8(opcode);
  213.   gennum8(scope);
  214.   gennum8(type);
  215.   gennum16(offset);
  216. }
  217.  
  218. /* ******************************************************************** */
  219. /* ******************* link phase ************************************* */
  220. /* ******************************************************************** */
  221.  
  222. static void label_fixup(), resolve_UnPgms(), link_pgms(), link_fas();
  223.  
  224. void link()
  225. {
  226.   label_fixup();
  227.   resolve_UnPgms(); link_pgms(); link_fas();
  228. }
  229.  
  230. /* ******************************************************************** */
  231. /* ***************** Forward referenced labels ************************ */
  232. /* ******************************************************************** */
  233.  
  234. typedef struct { address addr; int label; } FRlabel;
  235.  
  236. static int frlabels = 0;
  237. static declare_and_init_dTable(frlabel_table, FRlabel);
  238.  
  239. void addfref(addr,label) address addr;
  240. {
  241.   if (!xpand_dTable(&frlabel_table, 1, 100,100))
  242.   {
  243.     printf("Out of memory! Can't expand forward ref label table.\n");
  244.     exit(1);
  245.   }
  246.  
  247.   frlabel_table.table[frlabels].addr  = addr;
  248.   frlabel_table.table[frlabels].label = label;
  249.  
  250.   frlabels++;
  251. }
  252.  
  253. static void label_fixup()
  254. {
  255.   register int j;
  256.   register address addr, pc;
  257.  
  258.   for (j = 0; j < frlabels; j++)
  259.   {
  260.     pc   = frlabel_table.table[j].addr;
  261.     addr = getlabel(frlabel_table.table[j].label);
  262.     GENADDR(pc,addr);
  263.   }
  264. }
  265.  
  266. /* ******************************************************************** */
  267. /* ***************** Strings ****************************************** */
  268. /* ******************************************************************** */
  269.  
  270. extern char *savestr();
  271.  
  272. static declare_and_init_dTable(string_table, MuttCmd);
  273. static int strings = 0, soffset = 0, srepeats = 0;
  274.  
  275. static int add_string(string,save) char *string;
  276. {
  277.   register int j;
  278.   register MuttCmd *ptr;
  279.  
  280.   for (j = strings, ptr = string_table.table; j--; ptr++)
  281.     if (0 == strcmp(string,ptr->name)) { srepeats++; return ptr->token; }
  282.  
  283.   if (!xpand_dTable(&string_table, 1, 100,50))
  284.   {
  285.     printf("Out of memory! Can't expand string table.\n");
  286.     exit(1);
  287.   }
  288.   soffset += (1 + strlen(string));
  289.   string_table.table[strings].token = soffset;
  290.   if (save && (string = savestr(string)) == NULL) bail("Can't save string.");
  291.   string_table.table[strings].name = string;
  292.   strings++;
  293.  
  294.   return soffset;
  295. }
  296.  
  297. static void dump_strings(fptr) FILE *fptr;
  298. {
  299.   register int j;
  300.   register MuttCmd *ptr;
  301.  
  302.   for (j = strings, ptr = &string_table.table[j-1]; j--; ptr--)
  303.     fwrite(ptr->name,1,1+strlen(ptr->name),fptr);
  304. }
  305.  
  306. static int strings_size() { return soffset; }
  307.  
  308. /* ******************************************************************** */
  309. /* ************************* Unknown Programs ************************* */
  310. /* ******************************************************************** */
  311.  
  312. extern address getpgm();
  313.  
  314. typedef struct { char *name; address addr; int offset; } UnPgm;
  315.  
  316. static declare_and_init_dTable(unpgm_table, UnPgm);
  317. static int unpgms = 0, pfrefs = 0;
  318.  
  319. static int add_UnPgm(name) register char *name;
  320. {
  321.   register int j;
  322.  
  323.   pfrefs++;        /* another forward program reference */
  324.  
  325.   for (j = 0; j < unpgms; j++)    /* check to see if name already in table */
  326.     if (0 == strcmp(name,unpgm_table.table[j].name)) return j;
  327.  
  328.   if (!xpand_dTable(&unpgm_table, 1, 50,25))
  329.     bail("Out of memory! Can't expand unknown program table.");
  330.  
  331.   if (NULL == (unpgm_table.table[unpgms].name = savestr(name)))
  332.     bail("Can't save unpgm.");
  333.  
  334.   return unpgms++;
  335. }
  336.  
  337.    /* Find the address of the unknown programs.  If a program is still
  338.     *   unknown, add its name to the string table so it can be used for
  339.     *   runtime lookups.
  340.     */
  341. static void resolve_UnPgms()
  342. {
  343.   register UnPgm *pgm;
  344.   register int j;
  345.  
  346.   for (j = unpgms, pgm = unpgm_table.table; j--; pgm++)
  347.     if (NIL == (pgm->addr = getpgm(pgm->name)))
  348.       pgm->offset = add_string(pgm->name,FALSE);
  349. }
  350.  
  351. /* ******************************************************************** */
  352. /* *********************** Call Unknow Program ************************ */
  353. /* ******************************************************************** */
  354.  
  355. typedef struct { int unpgm;  address addr; } LinkTable;
  356.  
  357. static declare_and_init_dTable(pgm_link_table, LinkTable);
  358. static int pgm_unlinked = 0, pgm_unresolved = 0;
  359.  
  360. static void call_unknown_pgm(name) register char *name;
  361. {
  362.   if (!xpand_dTable(&pgm_link_table, 1, 50,50))
  363.     bail("Out of memory! Can't expand unknown program link table.");
  364.  
  365.   pgm_link_table.table[pgm_unlinked].unpgm = add_UnPgm(name);
  366.   pgm_link_table.table[pgm_unlinked].addr = pc;
  367.  
  368.   pgm_unlinked++;
  369. }
  370.  
  371.    /* Assumes:  resolve_UnPgms() has been called.
  372.     */
  373. static void link_pgms()
  374. {
  375.   address addr, pc;
  376.   register LinkTable *ltr;
  377.   register UnPgm *pgm;
  378.   register int j, offset;
  379.  
  380.   for (j = pgm_unlinked, ltr = pgm_link_table.table; j--; ltr++)
  381.   {
  382.     pgm = &unpgm_table.table[ltr->unpgm];
  383.     pc = ltr->addr;
  384.     if ((addr = pgm->addr) != NIL)        /* resolved */
  385.       { GENNUM8(PUSHADDR); GENADDR(pc,addr); }
  386.     else                    /* unresolved */
  387.     {
  388.       pgm_unresolved++;
  389.       GENNUM8(PUSHNAME);
  390.       offset = pgm->offset;
  391.       PUT_INT16(&compiled_code.table[pc],offset);
  392.     }
  393.   }
  394. }
  395.  
  396. /* ******************************************************************** */
  397. /* ************** Function addresses ********************************** */
  398. /* ******************************************************************** */
  399.  
  400. static declare_and_init_dTable(fa_link_table, LinkTable);
  401. static int fa_unlinked = 0;
  402.  
  403.     /* gen a fcn address */
  404. void genfa(addr,name) address addr; char *name;
  405. {
  406.   lst(FADDR,spoof(ebuf,"%s: %d (%s)",opname[PUSHADDR],addr,name));
  407.   gennum8(FADDR); gennum8(OPADDRESS);
  408.   if (addr == NIL)        /* probably a forward reference */
  409.   {
  410.     if (!xpand_dTable(&fa_link_table, 1, 10,5))
  411.     {
  412.       printf("Out of memory! Can't expand function address table.\n");
  413.       exit(1);
  414.     }
  415.     fa_link_table.table[fa_unlinked].unpgm = add_UnPgm(name);
  416.     fa_link_table.table[fa_unlinked].addr = pc;
  417.  
  418.     fa_unlinked++;
  419.   }
  420.   genaddr(pc,addr);
  421. }
  422.  
  423.     /* gen a fcn pointer */
  424. void genfp(opcode,n,name) char *name;
  425. {
  426.   switch (opcode)
  427.   {
  428.     case OPTOKEN: case OPXTOKEN:
  429.       lst(FADDR,spoof(ebuf,"%s: %d (%s)",
  430.         opname[(opcode == OPTOKEN) ? PUSHTOKEN : PUSHXT],n,name));
  431.       gennum8(FADDR); gennum8(opcode); gennum16(n);
  432.       break;
  433.     case OPNAME:
  434.       lst(FADDR,opname[PUSHNAME]);
  435.       gennum8(FADDR); gennum8(opcode);
  436.       break;
  437.   }
  438. }
  439.  
  440.    /* Assumes:  resolve_UnPgms() has been called.
  441.     */
  442. static void link_fas()
  443. {
  444.   address addr, pc;
  445.   register LinkTable *ltr;
  446.   register UnPgm *pgm;
  447.   register int j;
  448.  
  449.   for (j = fa_unlinked, ltr = fa_link_table.table; j--; ltr++)
  450.   {
  451.     pgm = &unpgm_table.table[ltr->unpgm];
  452.     pc = ltr->addr;
  453.     if ((addr = pgm->addr) != NIL) GENADDR(pc,addr);    /* resolved */
  454.     else                        /* unresolved */
  455.       moan(spoof(ebuf,
  456.     "(floc %s):  \"%s\" not defined in this file.",pgm->name,pgm->name));
  457.   }
  458. }
  459.  
  460. /* ******************************************************************* */
  461. /* ********************* Stats *************************************** */
  462. /* ******************************************************************* */
  463.  
  464. void dump_stats(fptr) FILE *fptr;
  465. {
  466.   fprintf(fptr,"%d strings totaling %d bytes, %d repeats.\n",
  467.     strings,strings_size(),srepeats);
  468.   fprintf(fptr,
  469.     "Unresolved function calls: %d (of %d forward references, %d unique).\n",
  470.     pgm_unresolved, pfrefs, unpgms);
  471.   fprintf(fptr,"Forward referenced labels: %d.\n",frlabels);
  472. }
  473.  
  474. /* ******************************************************************* */
  475. /* ********************* Dump the code ******************************* */
  476. /* ******************************************************************* */
  477.  
  478. address pgmaddr();
  479. char *pgmname(), *vname();
  480. unsigned int vtype();
  481.  
  482. void dumpcode(fname) char *fname;
  483. {
  484.   extern int errors;        /* in mc.c */
  485.  
  486.   address a;
  487.   char buf[90];
  488.   FILE *fptr;
  489.   uint8 bytes[50];    /* enough to hold the header and an address */
  490.   int j, z;
  491.   int16 n,pgmn = pgms();
  492.   unsigned int size, code_size;
  493.  
  494.   link();    /* !!! should really check for errors better */
  495.   if (errors) return;
  496.  
  497.   if (lstfile)        /* finish off the .lst file */
  498.   {
  499.     /* show entry points */
  500.     fputs("\n   PGM table\nADDRESS    NAME\n",lstfile);
  501.     fprintf(lstfile," %4d      entry point\n",entrypt);
  502.     for (j = 0; j < pgmn; j++)
  503.       fprintf(lstfile," %4d      %s\n",pgmaddr(j),pgmname(j));
  504.     /* global vars */
  505.     z = num_global_vars();
  506.     if (z == 0) fputs("\nNo global variables.\n",lstfile);
  507.     else
  508.     {
  509.       fputs("\n   Global Variables\nNAME                 OFFSET TYPE\n",
  510.     lstfile);
  511.       for (j = 0; j < z; j++)        /* global vars */
  512.     fprintf(lstfile,"%-20s %5d  %s\n",
  513.       vname(j),voffset(j),typename(vtype(j)));
  514.     }
  515.     fputc('\n',lstfile); dump_stats(lstfile);
  516.   }
  517.  
  518.   new_ext(buf,fname,".mco");
  519.   if ((fptr = fopen(buf,"wb")) == NULL) bail("Can't open output file");
  520.  
  521.     /*  figure out the size of the pgm name table */
  522.   for (j = n = z = 0; j < pgmn; j++)
  523.     if ((pgmflags(j) & HIDDEN) == 0) { n++; z += strlen(pgmname(j)) +1; }
  524.  
  525.     /* entry point is offset from start of code */
  526.   PUT_ADDRESS(&bytes[H_ENTRY_POINT],entrypt);
  527.   code_size = codesize();
  528.   size = code_size +strings_size() +z;
  529.   PUT_UINT16(&bytes[H_BYTES_OF_CODE],size);
  530.   PUT_UINT16(&bytes[H_NAME_TABLE_OFFSET],code_size);
  531.   PUT_INT16 (&bytes[H_NUMBER_OF_PGMS],n);
  532.   z = gvspace(); PUT_UINT16(&bytes[H_BYTES_OF_GVARS],z);
  533.   PUT_UINT8(&bytes[H_MAGIC_NUMBER],MM_MAGIC_NUMBER);
  534.   PUT_UINT16(&bytes[H_NUM_GLOBAL_OBJECTS],num_global_objects());
  535.  
  536.   fwrite((char *)bytes,1,BYTES_IN_HEADER,fptr);        /* write out header */
  537.   fwrite(compiled_code.table,1,codesize(),fptr);    /* dump the code */
  538.  
  539.   for (j = 0; j < pgmn; j++)            /* dump the name table */
  540.     if ((pgmflags(j) & HIDDEN) == 0)
  541.       fwrite(pgmname(j),1,strlen(pgmname(j))+1,fptr);
  542.   dump_strings(fptr);
  543.  
  544.   for (j = 0; j < pgmn; j++)            /* dump the pgm addresses */
  545.     if ((pgmflags(j) & HIDDEN) == 0)
  546.     {
  547.       a = pgmaddr(j); PUT_ADDRESS(bytes,a);
  548.       fwrite((char *)bytes,sizeof(address),1,fptr);
  549.     }
  550.  
  551.   fclose(fptr);
  552. }
  553.  
  554. /* ******************************************************************** */
  555. /* ******************************************************************** */
  556. /* ******************************************************************** */
  557. extern char *strcpy(), *strcat();
  558.  
  559. char *typename(type) unsigned int type;
  560. {
  561.   static char str[50];
  562.   int z = type & 0xFF;
  563.  
  564.   *str = '\0';
  565.   if (type == ARRAY)  strcat(str,"ARRAY");
  566.   if (type & POINTER) strcat(str,"POINTER to ");
  567.   if ((type & 0x80) == 0)        /* not a subtype */
  568.     switch (z)
  569.     {
  570.       case BLOB:    strcat(str,"BLOB");            break;
  571.       case FCNPTR:  strcat(str,"POINTER to FCN");    break;
  572.       case VOID:    strcat(str,"VOID");            break;
  573.       case STRING:  strcat(str,"STRING");        break;
  574.       case NUMBER:  strcat(str,"NUMBER");        break;
  575.       case BOOLEAN: strcat(str,"BOOLEAN");        break;
  576.       case REAL:    strcat(str,"REAL");            break;
  577.       case LIST:    strcat(str,"LIST");            break;
  578.     }
  579.   if (type & 0x80)        /* a subtype */
  580.     switch (z)
  581.     {
  582.       case INT8:  strcat(str,"byte");    break;
  583.       case INT16: strcat(str,"int");    break;
  584.       case INT32: strcat(str,"INT");    break;
  585.     }
  586. if (*str == '\0') strcpy(str,"*BOGUS*");
  587.   return str;
  588. }
  589.